package cn.bone.mima.rsa;

import org.apache.commons.io.FileUtils;

import javax.crypto.Cipher;
import java.io.File;
import java.security.*;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RsaDemo {

    public static void main(String[] args) throws Exception {

        String input = "今天好困啊abc";

        // 创建秘钥对 KeyPairGenerator
        String algorithm = "RSA";
        String pubPath = "e:/test/rsa/a.pub";
        String priPath = "e:/test/rsa/b.pri";
        // 生成秘钥并保存到文件中
        saveGenerateKey2File(algorithm, pubPath, priPath);

        // 从文件中读取公钥和私钥
        Key publicKey = readPublicKey(pubPath, algorithm);
        Key privateKey = readPrivateKey(priPath, algorithm);
        // 私钥加密
        String s = encryptRSA(algorithm, privateKey, input);
        System.out.println(s);
        // 公钥解密
        String result = decryptRSA(algorithm, publicKey, s);
        System.out.println(result);
    }

    /**
     * 生成公钥和私钥，并且保存到文本中
     * @param algorithm 算法
     * @param pubPath   公钥保存地址
     * @param priPath   私钥保存地址
     * @throws Exception
     */
    private static void saveGenerateKey2File(String algorithm,
                                             String pubPath,
                                             String priPath) throws Exception{
        KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance(algorithm);

        // 生成秘钥对
        KeyPair keyPair = pairGenerator.generateKeyPair();
        // 生成公钥和私钥
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        // 获取公钥的字节数组
        byte[] publicKeyEncoded = publicKey.getEncoded();
        // 获取私钥的字节数组
        byte[] privateKeyEncoded = privateKey.getEncoded();
        // 使用base64编码
        Base64.Encoder encoder = Base64.getEncoder();
        String publicKeyStr = encoder.encodeToString(publicKeyEncoded);
        String privateKeyStr = encoder.encodeToString(privateKeyEncoded);
        FileUtils.writeStringToFile(new File(pubPath), publicKeyStr, "UTF-8");
        FileUtils.writeStringToFile(new File(priPath), privateKeyStr, "UTF-8");
    }

    /**
     * 使用秘钥加密数据
     * @param algorithm     算法
     * @param privateKey    秘钥
     * @param input         原文
     * @return
     * @throws Exception
     */
    private static String encryptRSA(String algorithm,
                                     Key privateKey,
                                     String input) throws Exception{
        // 创建加密对象
        Cipher cipher1 = Cipher.getInstance(algorithm);
        // 对加密进行初始化
        // 第一个参数：加密的模式
        // 第二个参数：公钥或者私钥
        // 使用私钥进行加密
        cipher1.init(Cipher.ENCRYPT_MODE, privateKey);
        byte[] bytes = cipher1.doFinal(input.getBytes());
        String s = Base64.getEncoder().encodeToString(bytes);
        return s;
    }


    /**
     * 使用秘钥解密数据
     * @param algorithm     算法
     * @param publicKey    秘钥
     * @param input         密文
     * @return
     * @throws Exception
     */
    public static String decryptRSA(String algorithm,
                                    Key publicKey,
                                    String input) throws Exception {

        byte[] decode = Base64.getDecoder().decode(input);
        // 使用公钥进行解密
        Cipher cipher2 = Cipher.getInstance(algorithm);
        cipher2.init(Cipher.DECRYPT_MODE, publicKey);
        byte[] bytesResult = cipher2.doFinal(decode);
        String result = new String(bytesResult);
        return result;
    }

    /**
     * 读取私钥
     */
    public static PrivateKey readPrivateKey(String priPath, String algorithm) throws Exception{
        String priKeyString = FileUtils.readFileToString(new File(priPath), "UTF-8");
        byte[] decode = Base64.getDecoder().decode(priKeyString);
        // 创建key的工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // 创建私钥key的规则，需要注意这里使用的 keySpec 是 PKCS8EncodedKeySpec
        KeySpec keySpec = new PKCS8EncodedKeySpec(decode);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    /**
     * 读取公钥
     */
    public static PublicKey readPublicKey(String pubPath, String algorithm) throws Exception{
        String pubKeyString = FileUtils.readFileToString(new File(pubPath), "UTF-8");
        byte[] decode = Base64.getDecoder().decode(pubKeyString);
        // 创建key的工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // 创建公钥key的规则，需要注意这里使用的 keySpec 是 X509EncodedKeySpec
        KeySpec keySpec = new X509EncodedKeySpec(decode);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }
}
